#include <iostream>
#include <ostream>
#include <fstream>
#include <iomanip>
#include <stdio.h>
#include <filesystem>
#include "sndfile.h"


typedef struct
{
    int addr_offset;
    int length;
}wav_head_info;

using namespace std;
namespace fs = std::filesystem;

int read_wav(const char* wavPath,ofstream& soundOut);
void find_directory(const fs::path& path,vector<string*>& file_paths);

int main(int argc, char** argv)
{
    vector<wav_head_info*> wav_head_list;
    vector<string*> wav_path_list;
    char head_buff[128];
    ofstream bin_file;
    memset(head_buff,0,sizeof(head_buff));

    string out_file_path = argv[1];
    out_file_path = out_file_path + "\\DrummerSound.bin";

    // bin_file.open("DrummerSound.bin",ios::out | ios::binary);
    bin_file.open(out_file_path,ios::out | ios::binary);
    bin_file.write(head_buff,sizeof(head_buff));
    find_directory(fs::path(argv[1]),wav_path_list);
    int len=0;
    for(int i = 0;i < wav_path_list.size();i++)
    {
        wav_head_info *info = new wav_head_info;
        info->addr_offset = bin_file.tellp();
        len = read_wav(wav_path_list[i]->c_str(),bin_file);
        info->length = len;
        if(info->length > 0)
        {
            wav_head_list.push_back(info);
        }
        delete wav_path_list[i];
    }
    bin_file.seekp(0,ios::beg);
    int offset;
    head_buff[0] = wav_head_list.size() & 0x00FF;
    head_buff[1] = (wav_head_list.size() >> 8) & 0x00FF;
    head_buff[2] = 0;
    head_buff[3] = 0;
    offset = 4;
    for(int i=0; i<wav_head_list.size();i++)
    {
        //wav_head_list[i]->addr_offset += 0x20000;
        memcpy_s(head_buff+offset,sizeof(head_buff)-offset,((char*)wav_head_list[i]),sizeof(wav_head_info));
        offset += sizeof(wav_head_info);
    }
    bin_file.write(head_buff,sizeof(head_buff));
    bin_file.close();
    return 0;
}

void find_directory(const fs::path& path,vector<string*>& file_paths)
{
    if (fs::is_directory(path))
    {
        for (const auto &entry : fs::directory_iterator(path))
        {
            if (fs::is_directory(entry.path()))
            {
                // std::cout << "Directory: " << entry.path() << std::endl;
                find_directory(entry.path(),file_paths);
            }
            else
            {
                // std::cout << "File: " << entry.path() << std::endl;
                SF_INFO snd_info;
                SNDFILE *snd_file;

                snd_file = sf_open( entry.path().string().c_str(),SFM_READ,&snd_info);
                if(snd_file)
                {
                    sf_close(snd_file);
                    file_paths.push_back(new string(entry.path().string()));
                }
            }
        }
    }
}

int read_wav(const char* wavPath,ofstream& soundOut)
{
    SF_INFO snd_info;
    SNDFILE *snd_file;
    cout << "read file: " << wavPath;
    snd_file = sf_open(wavPath,SFM_READ,&snd_info);
    if(!snd_file)
    {
        cout << "error" << endl;
        return 0;
    }
    cout << "success!" << endl;
    if(snd_info.samplerate != 48000)
    {
        sf_close(snd_file);
        cout << "sample rate error" << endl;
        return 0;
    }

    short *sample_data = new short[snd_info.frames * snd_info.channels];
    sf_read_short(snd_file,sample_data,snd_info.frames * snd_info.channels);
    sf_close(snd_file);
    short *mono_data;
    if(snd_info.channels == 1)
    {
        mono_data = sample_data;
    }
    else
    {
        mono_data = new short[snd_info.frames];
        for(int i=0; i<snd_info.frames; i++)
        {
            mono_data[i] = sample_data[snd_info.channels * i];
        }
        delete[] sample_data;
    }
    soundOut.write((char*)mono_data,snd_info.frames*sizeof(short));
    delete[] mono_data;
    return (snd_info.frames*sizeof(short));
}
